`include "define.svh"

module div(
input wire				clk,
input wire				rst,

input wire								start_i,
input wire 								signed_i,
input wire [`REG_WIDTH - 1 : 0]			opprand1_i,
input wire [`REG_WIDTH - 1 : 0]			opprand2_i,

output reg [1 : 0]						status_o,							
output reg [`REG_WIDTH - 1 : 0]			result_o,
output reg [`REG_WIDTH - 1 : 0]			remainder_o
    );
    
    wire neg1 = (signed_i && opprand1_i[31]);
    wire neg2 = (signed_i && opprand2_i[31]);
    wire [31 : 0] opdata1 = (neg1) ? (~opprand1_i + 1) : opprand1_i;
    wire [31 : 0] opdata2 = (neg2) ? (~opprand2_i + 1) : opprand2_i;
    reg [5 : 0] cnt;
    reg [31 : 0] quotient;
    reg [63 : 0] remainder;
    reg [63 : 0] divisor;
    
    always @(posedge clk) begin
    	if (rst == `reset) begin
    		status_o <= `DIV_AVA;
    		result_o <= {`ZERO_REG, `ZERO_REG};
    	end
    	else if (status_o == `DIV_AVA && start_i) begin
    		quotient <= `ZERO_REG;
    		divisor <= {opdata2, `ZERO_REG};
    		remainder <= {`ZERO_REG, opdata1};
    		cnt <= 0;
    		status_o <= `DIV_RUN;
    	end
    	else if (status_o == `DIV_RUN && cnt != 33) begin
    		remainder <= ($unsigned(remainder) >= $unsigned(divisor)) ? remainder - divisor : remainder;
    		divisor <= ($unsigned(divisor) >> 1);
    		quotient <= ($unsigned(remainder) >= $unsigned(divisor)) ? {quotient[30 : 0], 1'b1} : {quotient[30 : 0], 1'b0};
    		cnt <= cnt + 1;
    	end
    	else if (cnt == 33) begin
    		status_o <= `DIV_DONE;
    		result_o <= (neg1 ^ neg2) ? (~quotient + 1) : quotient;
    		remainder_o <= neg1 ? (~remainder[31 : 0] + 1) : remainder[31 : 0];
    		cnt <= 0;
        end
        else if (status_o == `DIV_DONE) begin
            status_o <= `DIV_AVA;
        end 
    	else begin
    		status_o <= `DIV_AVA;
    		result_o <= {`ZERO_REG, `ZERO_REG};
    	end
    end
    
endmodule
